<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import HeaderBar from '../areas/HeaderBar/HeaderBar.vue';
import MainSidebar from '../areas/MainSidebar/MainSidebar.vue';
import AiSidebar from '../areas/AiSidebar/AiSidebar.vue';
import SettingsPanel from '../areas/SettingsPanel/SettingsPanel.vue';
import SettingsContent from '../areas/SettingsPanel/SettingsContent.vue';
import EditorArea from '../areas/Workspace/EditorArea.vue';
import BottomPanel from '../areas/BottomPanel/BottomPanel.vue';
import TerminalActions from '../areas/BottomPanel/TerminalActions.vue';
import ContextMenu from '../components/ContextMenu.vue';
import StatusBar from '../components/StatusBar.vue';
import { listModelKeys } from '../tauriApi';
import { getAppSetting, setAppSetting } from '../tauriApi';
import { theme, setColorTheme, getProductIcon } from '../assets/theme.js';
import { registerAction, registerShortcut, initHotkeys, triggerAction } from '../assets/hotkeys.js';
import { addRecentFile, addRecentFolder, getRecentFileByIndex, getRecentFolderByIndex } from '../assets/recents.js';
import { getCurrentContext } from '../assets/menus';
import { invoke } from '@tauri-apps/api/core';
import CommandPalette from '../components/CommandPalette.vue';
import { commandService } from '../services/commandService';
import { WorkspaceService } from '../services/WorkspaceService';
import { useRoute, useRouter } from 'vue-router';

const { t, locale } = useI18n();
const route = useRoute();
const router = useRouter();

// global shell state
const showSettings = ref(false);
const bottomActiveTab = ref('terminal');
const editorRef = ref(null);
const mainSidebarRef = ref(null);
const showAiPane = ref(true);
const showMainPane = ref(true);
const showBottomPane = ref(false);
const bottomHeight = ref(220);
const aiWidth = ref(420);
const mainWidth = ref(240);
const dragging = ref(false);
let dragStartX = 0;
let dragStartW = 420;

// theme & language
const colorMode = ref(theme.colorTheme);
const lang = ref(locale.value);

// chat side state
const modelKey = ref('');
const keys = ref([]);
const chatRef = ref(null);

async function refreshKeys() {
  keys.value = await listModelKeys();
  if (!modelKey.value && keys.value.length) modelKey.value = keys.value[0];
}

function onHandleMove(e) {
  const dx = e.clientX - dragStartX;
  let next = dragStartW - dx;
  if (next < 0) next = 0;
  if (next > 720) next = 720;
  aiWidth.value = next;
}

// hotkeys
let localHotkeyDisposers = [];
async function hydrateHotkeys() {
  // 仅清理本组件注册的快捷键，避免影响 menus.js 中为菜单注册的全局加速器
  try {
    for (const d of localHotkeyDisposers) {
      try { d && d(); } catch {}
    }
  } finally {
    localHotkeyDisposers = [];
  }
  let map = {};
  try {
    const raw = await getAppSetting('hotkeys');
    if (raw) map = JSON.parse(raw);
  } catch {}
    const fallback = {
      'toggle-ai': 'mod+j',
      'toggle-main': 'mod+b',
      // align with menubar View → Toggle Panel using backtick
      'toggle-bottom': 'mod+`',
      'open-settings': 'mod+,',
      'refresh-ai': 'f5',
      'focus-input': 'mod+/',
      // panel focus shortcuts (VS Code-like)
      'panel:terminal': 'mod+`',
      'panel:problems': 'mod+shift+m',
      'panel:output': 'mod+shift+u',
      // file operations
      'file:save': 'mod+s',
      'file:saveAs': 'mod+shift+s',
      // Command Palette
      'command:palette': 'mod+shift+p',
      'file:saveAll': 'mod+alt+s',
      'file:close': 'mod+w',
    };
  const cfg = { ...fallback, ...map };

  if (cfg['toggle-ai']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['toggle-ai'], action: 'toggle-ai' }));
  if (cfg['toggle-main']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['toggle-main'], action: 'toggle-main' }));
  if (cfg['toggle-bottom']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['toggle-bottom'], action: 'toggle-bottom' }));
  if (cfg['open-settings']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['open-settings'], action: 'open-settings' }));
  if (cfg['refresh-ai']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['refresh-ai'], action: 'refresh-ai', allowInInputs: true }));
  if (cfg['file:save']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['file:save'], action: 'file:save', allowInInputs: true }));
  if (cfg['file:saveAs']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['file:saveAs'], action: 'file:saveAs', allowInInputs: true }));
  if (cfg['file:saveAll']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['file:saveAll'], action: 'file:saveAll', allowInInputs: true }));
  if (cfg['file:close']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['file:close'], action: 'file:close', allowInInputs: true }));
  // Command Palette
  if (cfg['command:palette']) localHotkeyDisposers.push(registerShortcut({ combo: cfg['command:palette'], action: 'command:palette', allowInInputs: true }));
}

const timelineCmdDisposers = [];

// 提前注册核心动作（在子组件 mounted 之前可用）
registerAction('toggle-ai', () => { showAiPane.value = !showAiPane.value; });
registerAction('open-settings', () => { showSettings.value = true; });
registerAction('refresh-ai', () => { refreshKeys(); });
registerAction('toggle-main', () => { showMainPane.value = !showMainPane.value; });
registerAction('toggle-bottom', () => { showBottomPane.value = !showBottomPane.value; });
// Command Palette: delegate to commandService
registerAction('command:palette', () => { commandService.execute('workbench.action.showCommands'); });
registerAction('panel:problems', () => { bottomActiveTab.value = 'problems'; showBottomPane.value = true; });
registerAction('panel:output', () => { bottomActiveTab.value = 'output'; showBottomPane.value = true; });
registerAction('panel:terminal', () => { bottomActiveTab.value = 'terminal'; showBottomPane.value = true; });

// Register recent file/folder actions dynamically
for (let i = 0; i < 10; i++) {
  registerAction(`recent:open:folder:${i}`, async (evt) => {
    try {
      const path = getRecentFolderByIndex(i);
      if (path) {
        const isCtrlClick = !!(evt && evt.ctrlKey === true);
        if (isCtrlClick) {
          try {
            const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow');
            const label = `win-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
            const url = `index.html#/home?openFolder=${encodeURIComponent(String(path))}`;
            const win = new WebviewWindow(label, { 
              url,
              width: 1400,
              height: 900,
              center: true,
              resizable: true,
              decorations: false,
              title: `Editor - ${path}`
            });
            win.once('tauri://error', (e) => { console.error('Failed to create window', e); });
          } catch (err) {
            console.error('WebviewWindow not available or failed to open new window', err);
          }
        } else {
          // 在当前窗口打开
          await WorkspaceService.setRoot(String(path));
          showMainPane.value = true;
        }
      }
    } catch {}
  });
  registerAction(`recent:open:file:${i}`, async (evt) => {
    try {
      const path = getRecentFileByIndex(i);
      if (path) {
        const isCtrlClick = !!(evt && evt.ctrlKey === true);
        if (isCtrlClick) {
          try {
            const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow');
            const label = `win-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
            const url = `index.html#/home?openFile=${encodeURIComponent(String(path))}`;
            const win = new WebviewWindow(label, { 
               url,
               width: 1400,
               height: 900,
               center: true,
               resizable: true,
               decorations: false,
               title: `Editor - ${path}`
             });
            win.once('tauri://error', (e) => { console.error('Failed to create window', e); });
          } catch (err) {
            console.error('WebviewWindow not available or failed to open new window', err);
          }
        } else {
          // 在当前窗口打开
          editorRef.value?.openFileTab?.(path);
        }
      }
    } catch {}
  });
}
// File-like actions for menubar
registerAction('file:new', () => { try { editorRef.value?.newUntitledTab?.(); } catch {} });
registerAction('file:openFile', async () => {
  try {
    const { open } = await import('@tauri-apps/plugin-dialog');
    const r = await open({ multiple: false, directory: false });
    if (!r) return;
    const path = Array.isArray(r) ? r[0] : r;
    if (!path) return;
    await addRecentFile(path);
    editorRef.value?.openFileTab?.(path);
  } catch {}
});
registerAction('file:openFolder', async () => {
  try {
    const { open } = await import('@tauri-apps/plugin-dialog');
    const r = await open({ multiple: false, directory: true });
    if (!r) return;
    const path = Array.isArray(r) ? r[0] : r;
    if (!path) return;
    await addRecentFolder(path);
    await WorkspaceService.setRoot(String(path));
    showMainPane.value = true;
  } catch {}
});
registerAction('file:save', () => { try { editorRef.value?.saveActiveTab?.(); } catch {} });
registerAction('file:saveAs', () => { try { editorRef.value?.saveActiveTabAs?.(); } catch {} });
registerAction('file:saveAll', () => { try { editorRef.value?.saveAllTabs?.(); } catch {} });
registerAction('editor:format', () => { try { editorRef.value?.formatActiveModel?.(); } catch {} });
registerAction('file:close', () => { try { editorRef.value?.closeActiveTab?.(); } catch {} });

// Application-level actions
registerAction('app:about', () => {
  alert('Tauri Angular IDE\n\nBuilt with Tauri, Vue 3, and Monaco Editor');
});
registerAction('app:exit', async () => {
  try {
    const { getCurrentWebviewWindow } = await import('@tauri-apps/api/webviewWindow');
    await getCurrentWebviewWindow().close();
  } catch {}
});
registerAction('app:closeWindow', async () => {
  try {
    const { getCurrentWebviewWindow } = await import('@tauri-apps/api/webviewWindow');
    await getCurrentWebviewWindow().close();
  } catch {}
});
registerAction('app:preferences', () => { showSettings.value = true; });

// File system actions (explorer context menu)
registerAction('file:revealInExplorer', async () => {
  try {
    const ctx = getCurrentContext?.() || null;
    console.log('revealInExplorer - context:', ctx);
    const path = ctx?.node?.id || ctx?.file || editorRef.value?.getActiveFilePath?.();
    console.log('revealInExplorer - path:', path);
    if (!path) {
      console.warn('revealInExplorer - no path found');
      return;
    }
    const { revealItemInDir } = await import('@tauri-apps/plugin-opener');
    console.log('revealInExplorer - calling revealItemInDir with path:', String(path));
    await revealItemInDir(String(path));
    console.log('revealInExplorer - success');
  } catch (error) {
    console.error('revealInExplorer - error:', error);
  }
});
registerAction('file:openInTerminal', async () => {
  try {
    const ctx = getCurrentContext?.() || null;
    let target = ctx?.node?.id || ctx?.file || editorRef.value?.getActiveFilePath?.();
    if (!target) {
      // fall back to just focusing the terminal panel
      bottomActiveTab.value = 'terminal';
      showBottomPane.value = true;
      return;
    }
    const node = ctx?.node;
    const isDir = node ? (node.isDir === true || node.is_dir === true || node.isFolder === true) : false;
    let cwd = String(target);
    if (!isDir) {
      const s = String(target);
      const i = Math.max(s.lastIndexOf('/'), s.lastIndexOf('\\'));
      if (i > 0) cwd = s.slice(0, i);
    }
    // Focus terminal and show bottom panel
    bottomActiveTab.value = 'terminal';
    showBottomPane.value = true;
    // Create a new terminal in the target directory and activate it
    const { useTerminalsStore } = await import('../stores/terminals');
    const terms = useTerminalsStore();
    const t = terms.create({ name: 'Terminal', cwd });
    terms.activate(t.id);
  } catch {
    // ensure panel is visible even if something fails
    bottomActiveTab.value = 'terminal';
    showBottomPane.value = true;
  }
});

registerAction('file:openPath', async (arg) => {
  try {
    let path = '';
    let isCtrlClick = false;

    if (arg && typeof arg === 'object' && (arg.path || arg.uri)) {
      path = String(arg.path || arg.uri || '');
      isCtrlClick = !!(arg && arg.ctrlKey === true);
    } else {
      const evt = arg;
      const ctx = getCurrentContext?.() || null;
      const p = ctx?.node?.id || ctx?.file || null;
      if (!p) return;
      path = String(p || '');
      isCtrlClick = !!(evt && evt.ctrlKey === true);
    }

    if (!path) return;

    if (isCtrlClick) {
      try {
        const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow');
        const label = `win-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
        const url = `index.html#/home?openFile=${encodeURIComponent(path)}`;
        const win = new WebviewWindow(label, { 
           url,
           width: 1400,
           height: 900,
           center: true,
           resizable: true,
           decorations: false,
           title: `Editor - ${path}`
         });
        win.once('tauri://error', (e) => { console.error('Failed to create window', e); });
      } catch (err) {
        console.error('WebviewWindow not available or failed to open new window', err);
      }
    } else {
      editorRef.value?.openFileTab?.(path, { preview: false });
    }
  } catch {}
});

registerAction('file:revealInOS', async () => {
  try {
    const ctx = getCurrentContext?.() || null;
    const p = ctx?.node?.id || ctx?.file || editorRef.value?.getActiveFilePath?.();
    if (!p) return;
    const { revealItemInDir } = await import('@tauri-apps/plugin-opener');
    await revealItemInDir(String(p));
  } catch {}
});

registerAction('editor:revealActive', async () => {
  try {
    const p = editorRef.value?.getActiveFilePath?.();
    if (!p) return;
    const { revealItemInDir } = await import('@tauri-apps/plugin-opener');
    await revealItemInDir(String(p));
  } catch {}
});

// Tree inline actions and timeline
registerAction('explorer:refresh', () => { try { mainSidebarRef.value?.refresh?.(); } catch {} });

// Settings persistence
watch(colorMode, async (v) => { try { setColorTheme(String(v)); await setAppSetting('colorTheme', String(v)); } catch {} });
watch(lang, async (v) => { try { locale.value = String(v); await setAppSetting('language', String(v)); } catch {} });
watch(aiWidth, async (v) => { try { await setAppSetting('aiWidth', String(v)); } catch {} });
watch(mainWidth, async (v) => { try { await setAppSetting('mainWidth', String(v)); } catch {} });
watch(modelKey, async (v) => { try { await setAppSetting('modelKey', String(v)); } catch {} });
watch(showAiPane, async (v) => { try { await setAppSetting('showAiPane', v ? '1' : '0'); } catch {} });
watch(showMainPane, async (v) => { try { await setAppSetting('showMainPane', v ? '1' : '0'); } catch {} });
watch(showBottomPane, async (v) => { try { await setAppSetting('showBottomPane', v ? '1' : '0'); } catch {} });
watch(bottomHeight, async (v) => { try { await setAppSetting('bottomHeight', String(v)); } catch {} });
watch(bottomActiveTab, async (v) => { try { await setAppSetting('bottomActive', String(v)); } catch {} });

onMounted(async () => {
  // ensure global hotkey listener is bound once
  initHotkeys();

  // 动作注册完成后，使用 WorkspaceService 接管初始化
  try { await WorkspaceService.start(); } catch {}

  // register hotkeys and menu accelerators
  await hydrateHotkeys();

  // restore settings
  try { const v = await getAppSetting('colorTheme'); if (v) colorMode.value = v; } catch {}
  try { const v = await getAppSetting('language'); if (v) lang.value = v; } catch {}
  try { const v = await getAppSetting('aiWidth'); const n = v ? parseInt(v, 10) : NaN; if (!isNaN(n)) aiWidth.value = Math.max(0, Math.min(720, n)); } catch {}
  try { const v = await getAppSetting('mainWidth'); const n = v ? parseInt(v, 10) : NaN; if (!isNaN(n)) mainWidth.value = Math.max(0, Math.min(720, n)); } catch {}
  try { const v = await getAppSetting('modelKey'); if (v) modelKey.value = v; } catch {}
  try { const v = await getAppSetting('showAiPane'); if (v !== null && v !== undefined) showAiPane.value = (v === '1' || v === 'true'); } catch {}
  try { const v = await getAppSetting('showMainPane'); if (v !== null && v !== undefined) showMainPane.value = (v === '1' || v === 'true'); } catch {}
  try { const v = await getAppSetting('showBottomPane'); if (v !== null && v !== undefined) showBottomPane.value = (v === '1' || v === 'true'); } catch {}
  try { const v = await getAppSetting('bottomHeight'); const n = v ? parseInt(v, 10) : NaN; if (!isNaN(n)) bottomHeight.value = Math.max(120, Math.min(600, n)); } catch {}
  try { const v = await getAppSetting('bottomActive'); if (v) bottomActiveTab.value = String(v); } catch {}

  await refreshKeys();

  // 启动时如果带有 openFile 查询参数，则自动打开对应文件，并在打开后清除 URL 参数
  try {
    const q = route?.query?.openFile;
    const filePath = Array.isArray(q) ? String(q[0] || '') : String(q || '');
    if (filePath) {
      editorRef.value?.openFileTab?.(filePath, { preview: false });
      const newQuery = { ...route.query };
      delete newQuery.openFile;
      router.replace({ path: route.path, query: newQuery });
    }
  } catch {}

  // 启动时如果带有 openFolder 查询参数，则自动打开对应文件夹，并在打开后清除 URL 参数
  try {
    const fq = route?.query?.openFolder;
    const folderPath = Array.isArray(fq) ? String(fq[0] || '') : String(fq || '');
    if (folderPath) {
      await WorkspaceService.setRoot(String(folderPath));
      showMainPane.value = true;
      const newQuery = { ...route.query };
      delete newQuery.openFolder;
      router.replace({ path: route.path, query: newQuery });
    }
  } catch {}
});

onMounted(() => {
  registerAction('explorer:newFileInline', () => {
    try {
      const ctx = getCurrentContext?.() || null;
      const node = ctx?.node || null;
      try { mainSidebarRef.value?.beginNewFileInline?.(node); } catch {}
    } catch (error) {
      console.warn('Failed to trigger new file action:', error);
    }
  });
  registerAction('explorer:newFolderInline', () => {
    // Trigger inline folder creation in tree via MainSidebar tree ref
    try {
      const ctx = getCurrentContext?.() || null;
      const node = ctx?.node || null;
      try { mainSidebarRef.value?.beginNewFolderInline?.(node); } catch {}
    } catch (error) {
      console.warn('Failed to trigger new folder action:', error);
    }
  });
  registerAction('fs:rename', () => {
    try {
      const ctx = getCurrentContext?.() || null;
      const node = ctx?.node;
      if (!node || !node.id) return;
      try { mainSidebarRef.value?.beginRenameInline?.(node); } catch {}
    } catch (error) {
      console.warn('Failed to trigger rename action:', error);
    }
  });
  registerAction('fs:delete', async () => {
    try {
      const ctx = getCurrentContext?.() || null;
      const node = ctx?.node;
      if (!node || !node.id) return;
      // 确认删除对话框
      if (!confirm('Are you sure you want to delete this item? This action cannot be undone.')) return;
      // 调用 Tauri fs_delete 命令
      await invoke('fs_delete', { path: String(node.id), recursive: true });
      // 主动派发 fs-change 事件以驱动缓存失效和增量刷新
      try { window.dispatchEvent(new CustomEvent('fs-change', { detail: { event_type: 'delete', path: String(node.id) } })); } catch {}
      // 兜底：刷新文件树
      try { mainSidebarRef.value?.refresh?.(); } catch {}
    } catch (error) {
      console.error('Failed to delete:', error);
      alert('Failed to delete the file/folder: ' + String(error));
    }
  });
  // Tab context actions
  registerAction('editor:tab:close', () => { try { editorRef.value?.closeActiveTab?.(); } catch {} });
  registerAction('editor:tab:splitRight', () => { try { editorRef.value?.splitFocused?.('row'); } catch {} });
  registerAction('editor:tab:closeOthers', () => {
    try {
      const ctx = getCurrentContext?.() || null;
      const api = editorRef.value;
      if (!api || !ctx?.tab || !ctx?.groupId) return;
      api.__closeOthersExact?.(String(ctx.groupId), String(ctx.tab.id));
    } catch {}
  });
  registerAction('editor:tab:closeRight', () => {
    try {
      const ctx = getCurrentContext?.() || null;
      const api = editorRef.value;
      if (!api || !ctx?.tab || !ctx?.groupId) return;
      api.__closeRightExact?.(String(ctx.groupId), String(ctx.tab.id));
    } catch {}
  });
  registerAction('file:reopenClosed', () => { /* placeholder for Reopen Closed */ });
  // Context menu actions for tree
  registerAction('file:openFromTree', async (evt) => {
    try {
      // 统一委托到通用打开命令，确保行为一致（支持 Ctrl 新窗口等）
      await triggerAction('file:openPath', evt);
    } catch {}
  });
  
  // Problems panel context menu actions
  registerAction('problems:copyMessage', async () => {
    try {
      const ctx = getCurrentContext?.() || null;
      const problem = ctx?.problem;
      if (!problem || !problem.message) return;

      const payload = {
        id: problem.id,
        severity: problem.severity,
        message: problem.message,
        file: problem.file,
        line: problem.line,
        column: problem.column,
      };
      const text = JSON.stringify(payload);
      
      if (navigator.clipboard && navigator.clipboard.writeText) {
        await navigator.clipboard.writeText(text);
      } else {
        const textarea = document.createElement('textarea');
        textarea.value = text;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
      }
    } catch (error) {
      console.warn('Failed to copy problem message:', error);
    }
  });
  
  registerAction('problems:copyRelativePath', async () => {
    try {
      const ctx = getCurrentContext?.() || null;
      const problem = ctx?.problem;
      const file = ctx?.file || problem?.file;
      if (!file) return;
      
      if (navigator.clipboard && navigator.clipboard.writeText) {
        await navigator.clipboard.writeText(file);
      } else {
        const textarea = document.createElement('textarea');
        textarea.value = file;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
      }
    } catch (error) {
      console.warn('Failed to copy problem file path:', error);
    }
  });

  // Register timeline commands to call EditorArea APIs via editorRef, and dispose on unmount.
  try {
    // Ensure generic open command is available to all views via commandService
    timelineCmdDisposers.push(commandService.register('file:openPath', 'File: Open Path', async (arg) => {
      try {
        let path = '';
        let isCtrlClick = false;
        if (arg && typeof arg === 'object' && (arg.path || arg.uri)) {
          path = String(arg.path || arg.uri || '');
          isCtrlClick = !!(arg && arg.ctrlKey === true);
        } else {
          const ctx = getCurrentContext?.() || null;
          const p = ctx?.node?.id || ctx?.file || null;
          if (!p) return;
          path = String(p || '');
        }
        if (!path) return;
        if (isCtrlClick) {
          try {
            const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow');
            const label = `win-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
            const url = `index.html#/home?openFile=${encodeURIComponent(path)}`;
            const win = new WebviewWindow(label, { url, width: 1400, height: 900, center: true, resizable: true, decorations: false, title: `Editor - ${path}` });
            win.once('tauri://error', (e) => { console.error('Failed to create window', e); });
          } catch (err) {
            console.error('WebviewWindow not available or failed to open new window', err);
          }
        } else {
          editorRef.value?.openFileTab?.(path, { preview: false });
        }
      } catch {}
    }));

    // Restore mistakenly removed registrations
    timelineCmdDisposers.push(commandService.register('timeline.open', 'Timeline: Open', (p) => {
      try { editorRef.value?.openFileTab?.(String(p?.uri || ''), { preview: false }); } catch {}
    }));
    timelineCmdDisposers.push(commandService.register('timeline.restore', 'Timeline: Restore', (args) => {
      try { editorRef.value?.restoreFile?.(args); } catch {}
    }));

    timelineCmdDisposers.push(commandService.register('timeline.diff', 'Timeline: Diff', (args) => {
      try { editorRef.value?.diffFile?.(args); } catch {}
    }));
    // 新增：AI 时间线专用 Diff（基于 before/after 内容）
    timelineCmdDisposers.push(commandService.register('ai.timeline.diff', 'AI Timeline: Diff', (args) => {
      try { editorRef.value?.diffAiEntry?.(args); } catch {}
    }));
  } catch {}
});

onUnmounted(async () => {
  try {
    for (const d of timelineCmdDisposers) {
      try { d?.dispose?.(); } catch {}
    }
  } catch {}
  // 使用 WorkspaceService 停止副作用
  try { await WorkspaceService.stop(); } catch (error) { console.error('Failed to stop WorkspaceService:', error); }
});

</script>

<template>
  <div class="h-full min-h-0 flex flex-col bg-app-bg text-app-fg overflow-hidden">
    <!-- 标题栏 -->
    <HeaderBar
      :showMainPane="showMainPane"
      :showBottomPane="showBottomPane"
      :showAiPane="showAiPane"
      @toggleMain="() => showMainPane = !showMainPane"
      @toggleMaximize="async () => { try { const w = (await import('@tauri-apps/api/webviewWindow')).getCurrentWebviewWindow(); (await w.isMaximized()) ? w.unmaximize() : w.maximize(); } catch {} }"
      @toggleBottom="() => showBottomPane = !showBottomPane"
      @toggleAi="() => showAiPane = !showAiPane"
      @openSettings="() => editorRef?.openSettingsTab && editorRef.openSettingsTab()"
      @formatActive="() => { try { editorRef.value?.formatActiveModel?.(); } catch {} }"
    />

    <!-- 主内容区域 -->
    <main class="flex-1 min-h-0 relative grid overflow-hidden" style="grid-template-columns: auto 1fr auto;">
      <aside class="relative h-full border-r border-panel-border bg-panel-bg/60" v-show="showMainPane">
        <MainSidebar ref="mainSidebarRef" :show="showMainPane" :width="mainWidth" @update:width="(w)=> mainWidth = w" @select="(p, opts)=> {
            if (typeof p === 'object') {
              if (p.action) {
                if (p.action === 'open') {
                  editorRef?.openFileTab && editorRef.openFileTab(String(p.uri || ''), { preview: false });
                } else if (p.action === 'restore') {
                  editorRef?.restoreFile && editorRef.restoreFile(p);
                } else if (p.action === 'diff') {
                   editorRef?.diffFile && editorRef.diffFile(p);
                }
              } else if (p.path) {
                const filePath = String(p.path || '');
                editorRef?.openFileTab && editorRef.openFileTab(filePath, { preview: false });
                try {
                  const line = Number(p.line || p.row || 1);
                  const column = Number(p.col || p.column || 1);
                  const highlightLength = Number(p.highlightLength || 0);
                  const endLine = Number(p.endLine || 0) || undefined;
                  const endCol = Number(p.endCol || 0) || undefined;
                  // reveal location after opening, if API available
                  editorRef?.revealLocation && editorRef.revealLocation(filePath, line, column, highlightLength, endLine, endCol, {
                    source: 'search', // 来自搜索面板的定位请求
                    action: 'highlight'
                  });
                } catch {}
              } else {
                editorRef?.openFileTab && editorRef.openFileTab(String(p || ''), opts || {});
              }
            } else {
              editorRef?.openFileTab && editorRef.openFileTab(String(p || ''), opts || {});
            }
          }">
          <slot name="sidebar" />
        </MainSidebar>
      </aside>
      <section class="relative flex-1 min-h-0 overflow-hidden" style="grid-column: 2; grid-row: 1;">
        <EditorArea ref="editorRef" :bottomPad="showBottomPane ? (bottomHeight + 16) : 0">
          <template #default>
            <slot name="workspace" />
          </template>
        </EditorArea>
        <BottomPanel :open="showBottomPane" :height="bottomHeight" :active="bottomActiveTab" @update:active="(v)=> bottomActiveTab = v" @update:height="(h)=> bottomHeight = h" @close="() => showBottomPane = false" @navigate="(p)=> { try { editorRef.value?.revealLocation?.(p.file, p.line, p.column, 0, undefined, undefined, { source: 'problems', action: 'navigate' }); bottomActiveTab = 'problems'; showBottomPane.value = true; } catch {} }">
          <template #actions>
            <TerminalActions />
          </template>
        </BottomPanel>
      </section>
      <AiSidebar
        :modelKey="modelKey"
        :keys="keys"
        :show="showAiPane"
        :width="aiWidth"
        style="grid-column: 3; grid-row: 1;"
        @update:width="(v)=> aiWidth = v"
        @update:open="(v)=> showAiPane = v"
      />
    </main>

    <!-- 底部栏 -->
    <StatusBar />

    <!-- 其他组件 -->
    <ContextMenu />

    <SettingsPanel v-model:open="showSettings">
      <SettingsContent />
    </SettingsPanel>
  </div>
</template>


